
#ifndef __UDP_SERVER_H
#define __UDP_SERVER_H

#include <openssl/err.h>
#include <apr.h>
#include <apr_atomic.h>
#include <apr_file_io.h>
#include <apr_poll.h>
#include <apr_portable.h>
#include "../aprtools/APRMutex.h"
#include "netgeneral.h"

/** A struct shared between threads, a collection of pointers to
 * datagrams which allow communication between the listening server
 * side and the client handlers. The pointers on the pipes are NULL on
 * an inactive, waiting listening thread. */
typedef struct clientpipedatagrams
{
   /** The memory pool local to this thread. */
   apr_pool_t *localmp;
   /** The socket address associated with the client connected on this
    * thread. */
   apr_sockaddr_t cliaddr;
   /** Datagram pointer. */
   char *datagram_data;
   /** Datagram length. */
   int datagram_length;
   /** Finished with the datagram. */
   int complete;
   /** Client socket pointer. */
   apr_socket_t *clisock;
   /** Mutex for starting sessions. */
   APRMutex *sessionstart;
} ClientPipeDatagrams;

/** A basic UDP server class. This is the base class for all types of
 * servers. */
class UDPServer
{
   public:
      UDPServer(int inoofthreads, int iportno, const char *ihostname, apr_pool_t *upperpool);
      virtual ~UDPServer();
      int startListeningThread();
      int startSessionThreads();
      const char *getClientAddressAsStaticString(int threadid);
      /** Is the UDP server listening? */
      int isListening() { return (!listenstop); }
   protected:
      /** Pointer to an array of client pipes. */
      ClientPipeDatagrams *pipearray;
      /** The one listening thread. */
      apr_thread_t *listening_thread;
      /** The many per-session client threads. */
      apr_thread_t **session_threads;
      /** The thread attributes for the one listening thread. */
      apr_threadattr_t *listening_attr;
      /** The many thread attributes for the many client threads. */
      apr_threadattr_t **session_threadattrs;
      /** The memory pool. */
      apr_pool_t *mp;
      /** The number of client threads. */
      int noofthreads;
      /** Flag to be set by the server */
      int sessionstop;
   private:
      void acceptIncomingOnSocket(apr_pollset_t *pollset, apr_socket_t *lsock, apr_pool_t *mp);
      static void *handleServerListening(apr_thread_t *tthread, void *vthis);
      void handleClientsOnThread(int threadid, apr_pool_t *localmp);
      static void *handleClientsOnThreadStatic(apr_thread_t *tthread, void *args);
      /** Get the client handler as a function pointer. */
      virtual functor getClientHandlerFunction() const { return (functor)(&handleClientsOnThreadStatic); }
      int joinThreads();
      apr_socket_t *createListeningSocket(apr_pool_t *mp);
      /** Hostname for the listening server. */
      char *hostname;
      /** Port number for the listening server. */
      int portno;
      /** The time out for the listening server. */
      int timeout;
      /** Flag to be set by the listen to stop. */
      int listenstop;
};

#endif
